//-----------------------------------------------------------------------------
// File: CreateDevice.cpp
//
// Desc: First test on a graphics engine
//
//-----------------------------------------------------------------------------
#include <d3d9.h>
#include <d3dx9.h>
#include <windows.h>
#include <strsafe.h>
#include <Windows.h>
#include <mmsystem.h>
#include <math.h>
#include <stdio.h>
#include <cstdlib>
#include <iostream>
#include "MyCam.h"
#include "Vertex.h"
#include <list>
#include "GraphicsEngine.h"
#include "GeomBuilder.h"
#include "SceneRoot.h"
#include "RotationNode.h"
#include "TranslateNode.h"
#include "Terrain.h"
#include "TerrainSegment.h"
#include "PerlinNoise.h"
#include "ScaleNode.h"
#include "LTree.h"
#include "LGrammar.h"
#include "LGrammarRule.h"
#include "Terrain.h"
#include "KDTree.h"
#include "Ball.h"
#include "BlackBear.h"
#include "Spawner.h"
#include "TreeBuilder.h"

// Globals
HWND					g_hWnd = NULL;
UINT					g_message = NULL;
WPARAM					g_wParam = NULL; 
LPARAM					g_lParam = NULL;
MyCam					Cam;
Location				origin(0,0,0);
Player					player(origin, Cam);
LRESULT CALLBACK MsgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);

//-----------------------------------------------------------------------------
// Name: wWinMain()
// Desc: Creates the window
//-----------------------------------------------------------------------------

INT WINAPI wWinMain(HINSTANCE hInst, HINSTANCE, LPWSTR, INT)
{
	WNDCLASSEX wc = {sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L,
					GetModuleHandle(NULL), NULL, NULL, NULL, NULL,
					TEXT("Test"), NULL};
	RegisterClassEx(&wc);

	HWND hWnd = CreateWindow(TEXT("Test"), TEXT("First Engine Test"),
							WS_OVERLAPPEDWINDOW, 100, 100, 800, 800,
							GetDesktopWindow(), NULL, wc.hInstance, NULL);
	ShowWindow(hWnd, SW_SHOWDEFAULT);
	UpdateWindow(hWnd);
	GraphicsEngine Engine(hWnd, Cam);

	Location l(0,0,0);
	// Player player(l);
	KDTree spaceTree(10000,3000,10000,&player,l);

	Location loc(20,0,20);
	/*
	spaceTree.addObject(new Ball(100,loc));
	
	loc = *(new Location(-2,-2,-2));
	spaceTree.addObject(new Ball(2,loc));
	
	loc = *(new Location(-5,-5,-5));
	spaceTree.addObject(new Ball(2,loc));

	loc = *(new Location(-2.5,-2.5,-2.5));
	spaceTree.addObject(new Ball(2,loc));

	loc = *(new Location(25,0,25));
	spaceTree.addObject(new Ball(20,loc));

	loc = *(new Location(30,0,30));
	spaceTree.addObject(new Ball(20,loc));

	loc = *(new Location(15,0,15));
	spaceTree.addObject(new Ball(20,loc));

	loc = *(new Location(25,0,25));
	spaceTree.addObject(new Ball(20,loc));

	loc = *(new Location(25,0,-25));
	spaceTree.addObject(new Ball(40,loc));
	*/
	loc = *(new Location(-5,-20,40));
	Spawner<BlackBear> * bearSpawner = new Spawner<BlackBear>(&spaceTree, 1000.0f);
	bearSpawner->start();
	//spaceTree.addObject(new BlackBear(8,loc));

	PerlinNoise noise(1.10,2.0,8);

	/* std::list<WorldObject*> list = TreeBuilder::getTrees(-250.0f,250.0f,-250.0f, 250.0f);
	std::list<WorldObject*>::iterator it = list.begin();
	while(it != list.end()) {
		spaceTree.addObject(*(it++));
	}*/

	Vect3D inOne, inTwo, inThree;

	inOne.x = 0;
	inOne.y = 0;
	inOne.x = 0;

	inTwo.x = 0;
	inTwo.y = 0;
	inTwo.z = 10000;

	inThree.x = 10000;
	inThree.y = 0;
	inThree.z = 10000;

	loc = *(new Location(-32,1500,-32));
    spaceTree.addObject(new Cloud(loc,64,64));

	//spaceTree.addObject(new TerrainSegment(inOne,inTwo,inThree, 1000));
	
	std::list<WorldObject *> drawList = spaceTree.toDraw();

//	SceneRoot Tree = SceneRoot();

//	LGrammar gr = LGrammar();
//	gr.addRule(new LGrammarRule('L', "L[+L][**-L][/-L]"));
//	gr.setStartString("L");
//	LTree tree("L[+L][**-L][/-L]");
//	LTree tree(&gr);

//	Terrain * tGenerator = new Terrain(9);
//	std::list<WorldObject *> tSegs = tGenerator->getTerrain(0, 1000, 0, 1000);

	std::list<SceneRoot*> lToDraw;
	

	// SceneRoot Test = SceneRoot();
	// HAIR HAIR HAIR HAIR HAIR
	// Test.AddChild(BuildTri(inOne,inTwo,inThree));
	// Test.AddChild(BuildSphere(1.0,4,4));
	// lToDraw.push_back(&Test);


	int res = 100;

	std::list<WorldObject *>::iterator iter =  drawList.begin();

	while(iter != drawList.end() ) {
		lToDraw.push_back((*iter)->getDrawables());
		++iter;
    }
	
	/*Terrain *TestHill = new Terrain(res*res);
	Test.AddChild(TestHill->getGrid());*/


	/*TerrainSegment * tp1 = new TerrainSegment(Vect3D(10000,0,10000),Vect3D(10000,0,-10000),Vect3D(-10000,0,-10000), 10000000);
	TerrainSegment * tp2 = new TerrainSegment(Vect3D(10000,0,10000),Vect3D(-10000,0,-10000),Vect3D(-10000,0,10000), 10000000);*/
/*
	TerrainSegment * tpQ1L = new TerrainSegment(Vect3D(0,0,0),Vect3D(0,0,10000),Vect3D(10000,0,10000), 10000000);
	TerrainSegment * tpQ1R = new TerrainSegment(Vect3D(0,0,0),Vect3D(10000,0,0),Vect3D(10000,0,10000), 10000000);
	TerrainSegment * tpQ2L = new TerrainSegment(Vect3D(0,0,0),Vect3D(10000,0,-10000),Vect3D(10000,0,0), 10000000);
	TerrainSegment * tpQ2R = new TerrainSegment(Vect3D(0,0,0),Vect3D(10000,0,-10000),Vect3D(0,0,-10000), 10000000);
	TerrainSegment * tpQ3L = new TerrainSegment(Vect3D(0,0,0),Vect3D(-10000,0,0),Vect3D(-10000,0,-10000), 10000000);
	TerrainSegment * tpQ3R = new TerrainSegment(Vect3D(0,0,0),Vect3D(0,0,-10000),Vect3D(-10000,0,-10000), 10000000);
	TerrainSegment * tpQ4L = new TerrainSegment(Vect3D(0,0,0),Vect3D(-10000,0,0),Vect3D(-10000,0,10000), 10000000);
	TerrainSegment * tpQ4R = new TerrainSegment(Vect3D(0,0,0),Vect3D(0,0,10000),Vect3D(-10000,0,10000), 10000000);

	spaceTree.addObject(tpQ1L);
	spaceTree.addObject(tpQ1R);
	spaceTree.addObject(tpQ2L);
	spaceTree.addObject(tpQ2R);
	spaceTree.addObject(tpQ3L);
	spaceTree.addObject(tpQ3R);
	spaceTree.addObject(tpQ4L);
	spaceTree.addObject(tpQ4R);
*/
	/*spaceTree.addObject(tp1);
	spaceTree.addObject(tp2);*/
	/*
	std::list<WorldObject *> tSegs	= tpQ4R->split();
	iter = tSegs.begin();
	
	while(iter != tSegs.end() ) {
		//lToDraw.push_back((*iter)->getDrawables());
		WorldObject* tmp = (*iter);
		spaceTree.addObject(tmp);
		++iter;
    }
	*/


	MSG msg;
	ZeroMemory(&msg, sizeof(msg));
	while(msg.message != WM_QUIT)
	{
		if(PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
		else {
			Engine.Render(lToDraw);	
			spaceTree.update();
			spaceTree.unload();
			lToDraw.clear();
			drawList = spaceTree.toDraw();
			std::list<WorldObject *>::iterator drawIter =  drawList.begin();
			while(drawIter != drawList.end() ) {
				lToDraw.push_back((*drawIter)->getDrawables());
				++drawIter;
			}
		}
	}
	return 0;
}

//-----------------------------------------------------------------------------
// Name: MsgProc()
// Desc: Processes windows messages
//-----------------------------------------------------------------------------

LRESULT CALLBACK MsgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	Cam.HandleMessages(hWnd, message, wParam, lParam);
	switch(message)
	{
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
		break;
	}
	
	return DefWindowProc(hWnd, message, wParam, lParam);
}
